import { IApiItem } from '@/utils/interfaces'
import {
    Button,
    Checkbox,
    Menu,
    Message,
    Select,
    Space,
} from '@arco-design/web-react'
import {
    IconCopy,
    IconFile,
    IconFolder,
    IconUp,
} from '@arco-design/web-react/icon'
import React from 'react'
import Editor, { IEditorRef } from '../../components/Editor/Editor'
import { engineJs } from './utils/engineJs'
import {
    engineTs,
    engineTsCodeMap,
    IEngineTsCodeMapKeys,
} from './utils/engineTs'
import { indexJs } from './utils/indexJs'
import { indexTs } from './utils/indexTs'
import { methodsVue } from './utils/methodsVue'
import { piniaTs } from './utils/piniaTs'
import { setupTs } from './utils/setupTs'
import { typesTs } from './utils/typesTs'
import { useAppContextJs } from './utils/useAppContextJs'
import { useAppContextTs } from './utils/useAppContextTs'
import classNames from 'classnames'

export interface ICodeGenerateProps {
    // 数据
    apiItems: IApiItem[]
    // 类名
    className?: string
}

interface IMenuDataItem {
    type: 'menu' | 'submenu'
    key: string
    title: string
    children?: IMenuDataItem[]
}

// 菜单数据
const menusData: IMenuDataItem[] = [
    {
        type: 'submenu',
        key: 'folder-ts',
        title: 'ts',
        children: [
            {
                type: 'submenu',
                key: 'folder-repository-TS',
                title: 'repository',
                children: [
                    'index.ts',
                    'useAppContext.ts',
                    'types.ts',
                    'engine.ts',
                ].map((key) => ({
                    type: 'menu',
                    key,
                    title: key,
                })),
            },
            {
                type: 'submenu',
                key: 'store-pinia-TS',
                title: 'store',
                children: [
                    {
                        type: 'menu',
                        key: 'pinia.index.ts',
                        title: 'index.ts',
                    },
                ],
            },
            {
                type: 'menu',
                key: 'setup.ts',
                title: 'setup.vue',
            },
        ],
    },
    {
        type: 'submenu',
        key: 'folder-js',
        title: 'js',
        children: [
            {
                type: 'submenu',
                key: 'folder-repository-JS',
                title: 'repository',
                children: ['index.js', 'useAppContext.js', 'engine.js'].map(
                    (key) => ({
                        type: 'menu',
                        key,
                        title: key,
                    }),
                ),
            },
            {
                type: 'menu',
                key: 'methods.vue',
                title: 'methods.vue',
            },
        ],
    },
]

const generatorMap = {
    'useAppContext.ts': useAppContextTs,
    'index.ts': indexTs,
    'types.ts': typesTs,
    'engine.ts': engineTs,
    'engine.js': engineJs,
    'pinia.index.ts': piniaTs,
    'setup.ts': setupTs,
    'useAppContext.js': useAppContextJs,
    'index.js': indexJs,
    'methods.vue': methodsVue,
}

// 代码生成
const CodeGenerate: React.FC<ICodeGenerateProps> = ({
    apiItems,
    className,
}) => {
    // 是否隐藏代码生成组件
    const [isHidden, setIsHidden] = useState(true)
    // 编辑器实例
    const editorRef = useRef<IEditorRef | null>(null)
    // 被选中的apiId
    const [selectedApiIds, setSelectedApiIds] = useState<string[]>(
        apiItems.map((item) => item.id),
    )
    // 被选中的engineApiKey
    const [selectedEngineApiKeys, setSelectedEngineApiKeys] = useState<
        IEngineTsCodeMapKeys[]
    >(Object.keys(engineTsCodeMap) as IEngineTsCodeMapKeys[])
    // 在js中是否使用默认值
    const [useDefaultValuesInJs, setUseDefaultValuesInJs] = useState(true)
    // 当前选中的菜单
    const [selectedMenu, setSelectedMenu] = useState<string>('index.ts')

    // 选中菜单
    const handleSelectMenu = async (key: string) => {
        const generator = generatorMap[key as keyof typeof generatorMap]
        if (!generator) return
        const filteredApiItems = apiItems.filter((item) =>
            selectedApiIds.includes(item.id),
        )
        let content = ''
        if (key === 'engine.ts' || key === 'engine.js') {
            content = await (
                generator as unknown as (
                    keys: IEngineTsCodeMapKeys[],
                ) => Promise<string>
            )(selectedEngineApiKeys)
        } else {
            content = await (
                generator as (
                    keys: IApiItem[],
                    useDefaultValuesInJs?: boolean,
                ) => Promise<string>
            )(filteredApiItems, useDefaultValuesInJs)
        }
        editorRef.current?.setValue(content)
        // 格式化文档
        await editorRef.current?.format()
    }

    // 渲染菜单
    const renderMenu = (menuData?: IMenuDataItem[]) => {
        if (!menuData) return null
        return menuData.map((item) => {
            if (item.type === 'menu') {
                return (
                    <Menu.Item key={item.key}>
                        <IconFile /> {item.title}
                    </Menu.Item>
                )
            }
            return (
                <Menu.SubMenu
                    key={item.key}
                    title={
                        <>
                            <IconFolder /> {item.title}
                        </>
                    }
                >
                    {renderMenu(item.children)}
                </Menu.SubMenu>
            )
        })
    }

    // 点击复制
    const handleCopy = () => {
        const content = editorRef.current?.getValue()
        if (!content) return
        navigator.clipboard.writeText(content)
        Message.success('复制成功')
    }

    // 刷新
    const handleRefresh = () => {
        handleSelectMenu(selectedMenu)
    }

    // 当apiItems变化的时候设置成默认值
    useEffect(() => {
        setIsHidden(true)
        setUseDefaultValuesInJs(true)
        setSelectedApiIds(apiItems.map((item) => item.id))
        setSelectedEngineApiKeys(
            Object.keys(engineTsCodeMap) as IEngineTsCodeMapKeys[],
        )
        setSelectedMenu('index.ts')
    }, [apiItems])

    // 表单变化的时候重新生成代码
    useEffect(() => {
        if (isHidden) return
        handleSelectMenu(selectedMenu)
    }, [selectedApiIds, selectedEngineApiKeys, useDefaultValuesInJs, isHidden])

    if (isHidden) {
        return (
            <div
                className={classNames(
                    className,
                    'flex justify-center items-center h-full',
                )}
            >
                <Button onClick={() => setIsHidden(false)}>代码生成</Button>
            </div>
        )
    }

    return (
        <div className={className}>
            {/* 折叠按钮 */}
            <div className='flex justify-center items-center mb-2'>
                <Button icon={<IconUp />} onClick={() => setIsHidden(true)} />
            </div>
            {/* 内容 */}
            <div className='flex-1 flex max-h-[90vh] min-h-[500px] border-1 border-solid border-gray-200 rounded overflow-hidden'>
                {/* 文件列表 */}
                <Menu
                    selectedKeys={[selectedMenu]}
                    className='w-[240px] border-1 border-solid border-gray-200'
                    onClickMenuItem={(key) => {
                        setSelectedMenu(key)
                        handleSelectMenu(key)
                    }}
                >
                    {renderMenu(menusData)}
                </Menu>
                {/* 内容 */}
                <div className='flex-1'>
                    {/* 菜单栏 */}
                    <div className='p-2 w-full flex items-center flex-wrap gap-2'>
                        {/* 选择api */}
                        选择API:{' '}
                        <Select
                            value={selectedApiIds}
                            onChange={(value) => {
                                setSelectedApiIds(value)
                            }}
                            className='w-[300px]'
                            options={apiItems.map((item) => ({
                                label: item.label,
                                value: item.id,
                            }))}
                            mode='multiple'
                            maxTagCount={0}
                            allowClear
                            filterOption={(input, option) => {
                                const { value: id } = option.props as {
                                    value: string
                                }
                                const item = apiItems.find(
                                    (item) => item.id === id,
                                )
                                if (!item) return false
                                const loverCasedInput = input.toLowerCase()
                                return (
                                    item.label
                                        .toLowerCase()
                                        .includes(loverCasedInput) ||
                                    item.url
                                        ?.toLowerCase()
                                        .includes(loverCasedInput) ||
                                    false
                                )
                            }}
                        />
                        {/* 选择engineApi */}
                        选择engineApi:{' '}
                        <Select
                            value={selectedEngineApiKeys}
                            onChange={(value) => {
                                setSelectedEngineApiKeys(value)
                            }}
                            className='w-[300px]'
                            options={Object.keys(engineTsCodeMap).map(
                                (item) => ({
                                    label: item,
                                    value: item,
                                }),
                            )}
                            mode='multiple'
                            maxTagCount={0}
                            allowClear
                        />
                        {/* 在js中是否使用默认值 */}
                        在js中使用默认值:{' '}
                        <Checkbox
                            checked={useDefaultValuesInJs}
                            onChange={(value) => {
                                setUseDefaultValuesInJs(value)
                            }}
                        />
                        <div className='flex gap-2 ml-auto'>
                            <Button onClick={handleRefresh}>刷新</Button>
                            {/* 复制按钮 */}
                            <Button icon={<IconCopy />} onClick={handleCopy}>
                                复制到剪贴板
                            </Button>
                        </div>
                    </div>
                    {/* 内容预览 */}
                    <Editor
                        editorRef={editorRef}
                        language='typescript'
                        height='100%'
                        options={{
                            fontSize: 12,
                        }}
                    />
                </div>
            </div>
        </div>
    )
}

export default CodeGenerate
